<?php
namespace ITSociaal\Themes\Houtgrutter;

class RenderController
{
	/** @var \ITSociaal\Themes\Houtgrutter\Util */
	protected $util;

	/** @var string */
	protected $result;

	/** @var \ITSociaal\Themes\Houtgrutter\RendererInterface[] */
	protected $renderers = [];

	/** @var \ITSociaal\Themes\Houtgrutter\PostProcessorInterface[] */
	protected $postprocessors = [];

	/**
	 * Calls the given renderers
	 *
	 * @return \Generator
	 */
	protected function generateRendererResult()
	{
		$renderers = $this->getRenderers();

		return $this->getUtil()->generateResultPerArgument(
			$renderers,
			[$this, "renderObject"]
		);
	}

	/**
	 * Call the given post-processors
	 *
	 * @return \Generator
	 */
	protected function generatePostProcessorResult()
	{
		return $this->getUtil()->generateResultPerArgument(
			$this->getPostProcessors(),
			[$this, "postprocessObject"]
		);
	}

	/**
	 * @return \ITSociaal\Themes\Houtgrutter\Util
	 */
	protected function getUtil()
	{
		return $this->util;
	}

	/**
	 * Calls a RendererInterface object
	 *
	 * @param \ITSociaal\Themes\Houtgrutter\RendererInterface $obj
	 *
	 * @return string
	 * @throws \ITSociaal\Themes\Houtgrutter\Exception\InvalidRendererException
	 */
	public function renderObject($obj)
	{
		if (!is_a($obj, RendererInterface::class)) {
			throw new Exception\InvalidRendererException;
		}

		return $obj->render();
	}

	/**
	 * Calls a PostProcessorInterface object
	 *
	 * @param \ITSociaal\Themes\Houtgrutter\PostProcessorInterface $obj
	 * @param string                                               $input
	 *
	 * @return string
	 * @throws \ITSociaal\Themes\Houtgrutter\Exception\InvalidPostProcessorException
	 */
	public function postprocessObject($obj, $input = null)
	{
		if (!is_a($obj, PostProcessorInterface::class))
			throw new Exception\InvalidPostProcessorException;

		$input = $input ?: $this->getResult();

		return $obj->post($input);
	}

	/**
	 * Calls the available RendererInterfaces and validates their result
	 *
	 * Stops on the first available valid result
	 *
	 * @return self
	 */
	public function performRendering()
	{
		foreach($this->generateRendererResult() as $result) {
			if (is_null($result))
				continue;
			else {
				assert(is_string($result));
				$this->setResult($result);
				break;
			}
		}

		return $this;
	}

	/**
	 * Calls the available PostProcessors and uses their result consecutively
	 *
	 * @return self
	 */
	public function performPostProcessing()
	{
		foreach($this->generatePostProcessorResult() as $result) {
			assert(is_string($result));
			$this->setResult($result);
		}

		return $this;
	}

	/**
	 * @return string
	 * @throws \ITSociaal\Themes\Houtgrutter\Exception\RuntimeException
	 */
	public function getResult()
	{
		$ret = $this->result;

		if (is_null($ret)) {
			throw new Exception\RuntimeException("No result defined yet");
		}

		return $ret;
	}

	/**
	 * @param string
	 *
	 * @return self
	 */
	protected function setResult($result)
	{
		$this->result = strval($result);

		return $this;
	}

	/**
	 * @param \ITSociaal\Themes\Houtgrutter\RendererInterface $renderer
	 *
	 * @return self
	 */
	public function addRenderer(RendererInterface $renderer)
	{
		$this->renderers[] = $renderer;

		return $this;
	}

	/**
	 * @return \ITSociaal\Themes\Houtgrutter\RendererInterface[]
	 * @throws \ITSociaal\Themes\Houtgrutter\Exception\RuntimeException
	 */
	public function getRenderers()
	{
		$ret = $this->renderers;

		if (empty($ret)) {
			throw new Exception\RuntimeException(
				"No renderers defined"
			);
		}

		return $ret;
	}

	/**
	 * @param \ITSociaal\Themes\Houtgrutter\PostProcessorInterface $postprocessor
	 *
	 * @return self
	 */
	public function addPostProcessor(PostProcessorInterface $postprocessor)
	{
		$this->postprocessors[] = $postprocessor;

		return $this;
	}

	/**
	 * @return \ITSociaal\Themes\Houtgrutter\PostProcessorInterface[]
	 */
	public function getPostProcessors()
	{
		return $this->postprocessors;
	}

	/**
	 * @param \ITSociaal\Themes\Houtgrutter\Util $util
	 */
	public function __construct(Util $util)
	{
		$this->util = $util;
	}
}

/* vi:set ts=4 sw=4 noet: */
